package com.atguigu.tingshu.common.login;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import jakarta.servlet.http.HttpServletRequest;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;


@Component
@Aspect
public class LoginAspect {

    /**
     * 增强方法：登录验证token
     *
     * @param point
     * @return
     */
    @SneakyThrows
    @Around("@annotation(com.atguigu.tingshu.common.login.GuiguLogin)")
    public Object loginCheck(ProceedingJoinPoint point) {
        // 获取当前执行的方法对象的签名
        MethodSignature signature = (MethodSignature) point.getSignature();
        // 获取方法对象
        Method method = signature.getMethod();
        // 获取方法上的注解
        GuiguLogin guiguLogin = method.getAnnotation(GuiguLogin.class);
        // 判断是否需要登录
        if (guiguLogin.isLogin()) {
            // 获取用户Request对象
            ServletRequestAttributes requestAttributes =
                    (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = requestAttributes.getRequest();
            // 验证requestHeader是否携带token
            String token = request.getHeader("token");
            // 没有携带转去登录页面
            if (StringUtils.isEmpty(token)) {
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
            // 解析验证token
            try {
                // 解析jwt
                Jwt jwt = JwtHelper.decodeAndVerify(token, new RsaVerifier(SystemConstant.PUBLIC_KEY));
                // 获取荷载
                String claims = jwt.getClaims();
                // 反序列化
                JSONObject jsonObject = JSONObject.parseObject(claims, JSONObject.class);
                // 获取用户的登录时间 -- 改为手动校验token失效-更新
                // 获取用户id
                Long userId = Long.valueOf(jsonObject.get("userId").toString());
                // 获取用户VIP状态 -- 通过vip过期时间判断
                Long vipExpireTime = Long.valueOf(jsonObject.get("vipExpireTime").toString());
                // 存储用户vip状态
                if (vipExpireTime > System.currentTimeMillis()) {
                    // 未过期 有效
                    AuthContextHolder.setVip(1);
                } else {
                    // 过期 无效
                    AuthContextHolder.setVip(0);
                }
                // 本地线程工具类：存储用户id
                AuthContextHolder.setUserId(userId);
            } catch (Exception e) {
                // 令牌不合法则跳转至登录页面
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
        }
        // 获取方法的参数
        Object[] args = point.getArgs();
        // 执行方法
        Object proceed = point.proceed(args);
        // 清理本地线程的userId
        AuthContextHolder.removeUserId();
        // 返回
        return proceed;
    }
}
